package cn.k7g.alloy.mybatis.typehandler;

import cn.k7g.alloy.core.ext.FlagCode;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.lang.reflect.Method;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;

/**
 * 对于mybatis支持  Set<FlagCode>
 * @date  2022/7/27 下午5:55
 * @author victor-wu
 */
public class FlagTypeHandler<T> extends BaseTypeHandler<Set<? extends FlagCode>> {
    private Class<T> clazz;

    public FlagTypeHandler(Class<T> clazz) {
        if (clazz == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }
        this.clazz = clazz;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Set<? extends FlagCode> parameter, JdbcType jdbcType) throws SQLException {
        ps.setInt(i, this.toJson(parameter));
    }

    @Override
    public Set<? extends FlagCode> getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return this.toObject(rs.getInt(columnName));
    }

    @Override
    public Set<? extends FlagCode> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return this.toObject(rs.getInt(columnIndex));
    }

    @Override
    public Set<? extends FlagCode> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return this.toObject(cs.getInt(columnIndex));
    }

    private Integer toJson(Set<? extends FlagCode> object) {
        if (object == null) {
            return null;
        }
        int result = 0;
        for (FlagCode item : object) {
            result |= item.getCode();
        }
        return result;
    }

    private Set<FlagCode> toObject(Integer content) {
        try {
            if (content == null) {
                return new HashSet<>();
            }
            Method values = this.clazz.getDeclaredMethod("values");
            FlagCode[] invoke = (FlagCode[]) values.invoke(null);
            Set<FlagCode> result = new HashSet<>();
            for (FlagCode item : invoke) {
                if ((item.getCode() & content) != 0) {
                    result.add(item);
                }
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
